package com.xinzhidi.util;

import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.*;
import com.xinzhidi.config.AliyunConfig;
import com.xinzhidi.model.FileBusiness;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/***
 * @author cx
 * @date 2023/4/23 10:08
 */
public class OSSUtil {
    /**
     * log日志
     */
    private static final Logger logger = LoggerFactory.getLogger(OSSUtil.class);


    /**
     * 获取oss
     *
     * @return
     */
    public static OSS getOSSClient() {
        return new OSSClientBuilder().build(AliyunConfig.getEndpoint(), AliyunConfig.getAccessId(), AliyunConfig.getAccessKey());
    }

    /**
     * 上传图片
     *
     * @param url
     * @throws
     */
    public void uploadImg2Oss(String url) throws IOException {
        File fileOnServer = new File(url);
        FileInputStream fin;
        try {
            fin = new FileInputStream(fileOnServer);
            String[] split = url.split("/");
            this.uploadFile2OSS(fin, split[split.length - 1]);
        } catch (FileNotFoundException e) {
            throw new IOException("图片上传失败");
        }
    }

    public FileBusiness uploadImg2Oss(MultipartFile file, Integer businessType) throws IOException {
        if (file.getSize() > 5 * 1024 * 1024) {
            throw new IOException("上传图片大小不能超过5M！");
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        // 获取文件名
        String originalFilename = file.getOriginalFilename();
        // 获取文件后缀名
        String suffixName = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();
        // 最后上传生成的文件名
        String finalFileName = System.currentTimeMillis() + "" + new SecureRandom().nextInt(0x0400) + suffixName;
        // oss中的文件夹名
        String objectName = sdf.format(new Date()) + "/" + finalFileName;

        FileBusiness fileBusiness = new FileBusiness();
        fileBusiness.setBusinessType(businessType);
        fileBusiness.setFileName(originalFilename);
        fileBusiness.setFileServiceName(finalFileName);
        fileBusiness.setFileSuffix(suffixName);
        fileBusiness.setFileSize(file.getSize());
        fileBusiness.setOutsideChain(getImgUrl(objectName));
        try {
            InputStream inputStream = file.getInputStream();
            this.uploadFile2OSS(inputStream, objectName);
            return fileBusiness;
        } catch (Exception e) {
            e.printStackTrace();
            throw new IOException("图片上传失败");
        }
    }

    /**
     * 获得图片路径
     *
     * @param fileUrl
     * @return
     */
    public String getImgUrl(String fileUrl) {
        System.out.println(fileUrl);
        if (!StringUtils.isEmpty(fileUrl)) {
//            String[] split = fileUrl.split("/");
            return this.getUrl(AliyunConfig.getDir() + fileUrl);
        }
        return "";
    }

    /**
     * 上传到OSS服务器 如果同名文件会覆盖服务器上的
     *
     * @param instream 文件流
     * @param fileName 文件名称 包括后缀名
     * @return 出错返回"" ,唯一MD5数字签名
     */
    public String uploadFile2OSS(InputStream instream, String fileName) {

        String ret = "";
        try {
            OSS ossClient = getOSSClient();
            // 创建上传Object的Metadata
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(instream.available());
            objectMetadata.setCacheControl("no-cache");
            objectMetadata.setContentType(getContentType(fileName.substring(fileName.lastIndexOf("."))));
            objectMetadata.setHeader("Pragma", "no-cache");
//            objectMetadata.setContentDisposition("inline;filename=" + fileName);
            // 上传文件
            PutObjectResult putResult = ossClient.putObject(AliyunConfig.getBucket(), AliyunConfig.getDir() + fileName, instream, objectMetadata);
            ret = putResult.getETag();
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        } finally {
            try {
                if (instream != null) {
                    instream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return ret;
    }

    /**
     * 通过文件名判断并获取OSS服务文件上传时文件的contentType
     *
     * @param filenameExtension 文件名
     * @return 文件的contentType
     */
    public static final String getContentType(String filenameExtension) {

        if (filenameExtension.equalsIgnoreCase(".bmp")) {
            return "application/x-bmp";
        }
        if (filenameExtension.equalsIgnoreCase(".gif")) {
            return "image/gif";
        }
        if (filenameExtension.equalsIgnoreCase(".jpeg") ||
                filenameExtension.equalsIgnoreCase(".jpg") ||
                filenameExtension.equalsIgnoreCase(".png")) {
            return "image/jpg";
        }
        if (filenameExtension.equalsIgnoreCase(".html")) {
            return "text/html";
        }
        if (filenameExtension.equalsIgnoreCase(".txt")) {
            return "text/plain";
        }
        if (filenameExtension.equalsIgnoreCase(".vsd")) {
            return "application/vnd.visio";
        }
        if (filenameExtension.equalsIgnoreCase(".pptx") ||
                filenameExtension.equalsIgnoreCase(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (filenameExtension.equalsIgnoreCase(".docx") ||
                filenameExtension.equalsIgnoreCase(".doc")) {
            return "application/msword";
        }
        if (filenameExtension.equalsIgnoreCase(".xla") ||
                filenameExtension.equalsIgnoreCase(".xlc") ||
                filenameExtension.equalsIgnoreCase(".xlm") ||
                filenameExtension.equalsIgnoreCase(".xls") ||
                filenameExtension.equalsIgnoreCase(".xlt") ||
                filenameExtension.equalsIgnoreCase(".xlw")) {
            return "application/vnd.ms-excel";
        }
        if (filenameExtension.equalsIgnoreCase(".xlsx")) {
            return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
        }
        if (filenameExtension.equalsIgnoreCase(".xml")) {
            return "text/xml";
        }
        if (filenameExtension.equalsIgnoreCase(".pdf")) {
            return "application/pdf";
        }
        if (filenameExtension.equalsIgnoreCase(".zip")) {
            return "application/zip";
        }
        if (filenameExtension.equalsIgnoreCase(".tar")) {
            return "application/x-tar";
        }
        if (filenameExtension.equalsIgnoreCase(".avi")) {
            return "video/avi";
        }
        if (filenameExtension.equalsIgnoreCase(".mp4")) {
            return "video/mpeg4";
        }
        if (filenameExtension.equalsIgnoreCase(".mp3")) {
            return "audio/mp3";
        }
        if (filenameExtension.equalsIgnoreCase(".mp2")) {
            return "audio/mp2";
        }
        // 默认下载
//        return "application/octet-stream";
        return "image/jpg";
    }


    /**
     * 获得url链接
     *
     * @param key
     * @return
     */
    public String getUrl(String key) {
        // 设置URL过期时间为10年 3600l* 1000*24*365*10
        OSS ossClient = getOSSClient();
        Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 10);
        // 生成URL
        URL url = ossClient.generatePresignedUrl(AliyunConfig.getBucket(), key, expiration);
        System.out.println("url: " + url);
        if (url != null) {
            String host = "http://" + url.getHost() + url.getPath();
            System.out.println("host: " + host);
            // http://wxcall-xiaobanben.oss-cn-shenzhen.aliyuncs.com/image/20220129/1643469496754508.jpg
            return host;
        }
        return "";
    }

    /**
     * 获取文件夹
     *
     * @param fileName
     * @return
     */
    public List<String> fileFolder(String fileName) {
        // 创建OSSClient实例。
        OSS ossClient = getOSSClient();
        // 构造ListObjectsRequest请求。
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest(AliyunConfig.getBucket());

        // 设置正斜线（/）为文件夹的分隔符。
        listObjectsRequest.setDelimiter("/");
        // 设置prefix参数来获取fun目录下的所有文件。
        if (!StringUtils.isEmpty(fileName)) {
            listObjectsRequest.setPrefix(fileName + "/");
        }
        // 列出文件
        ObjectListing listing = ossClient.listObjects(listObjectsRequest);
        // 遍历所有commonPrefix
        List<String> list = new ArrayList<>();
        for (String commonPrefix : listing.getCommonPrefixes()) {
            String newCommonPrefix = commonPrefix.substring(0, commonPrefix.length() - 1);
            String[] s = newCommonPrefix.split("/");
            if (!StringUtils.isEmpty(fileName)) {
                list.add(s[s.length - 1]);
            } else {
                list.add(s[0]);
            }
        }
        // 关闭OSSClient
        ossClient.shutdown();
        return list;
    }

    /**
     * 列举文件下所有的文件url信息
     */
    public ObjectListing listFile2(String fileHost, String nextMarker) {
        // 创建OSSClient实例。
        OSS ossClient = getOSSClient();

        // 构造ListObjectsRequest请求。
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest(AliyunConfig.getBucket());

        // 设置正斜线（/）为文件夹的分隔符。
        listObjectsRequest.setDelimiter("/");
        // 列出fun目录下的所有文件和文件夹。
        listObjectsRequest.setPrefix(fileHost + "/");

        ObjectListing listing = ossClient.listObjects(listObjectsRequest);

        // 遍历所有文件。
        System.out.println("Objects:");
        // objectSummaries的列表中给出的是fun目录下的文件。
        for (OSSObjectSummary objectSummary : listing.getObjectSummaries()) {
            System.out.println(objectSummary.getKey());
        }

        // 遍历所有commonPrefix。
        System.out.println("\nCommonPrefixes:");
        // commonPrefixs列表中显示的是fun目录下的所有子文件夹。由于fun/movie/001.avi和fun/movie/007.avi属于fun文件夹下的movie目录，因此这两个文件未在列表中。
        for (String commonPrefix : listing.getCommonPrefixes()) {
            System.out.println(commonPrefix);
        }

        // 关闭OSSClient。
        ossClient.shutdown();
        return listing;
    }

    /**
     * 列举文件下所有的文件url信息
     */
    public List<String> listFile(String fileHost, String nextMarker) {
        // 创建OSSClient实例。
        OSS ossClient = getOSSClient();
        // 构造ListObjectsRequest请求
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest(AliyunConfig.getBucket());

        // 设置prefix参数来获取fun目录下的所有文件。
        listObjectsRequest.setPrefix(fileHost + "/");
        listObjectsRequest.setMarker(nextMarker);

        // 列出文件。
        ObjectListing listing = ossClient.listObjects(listObjectsRequest);
        // 遍历所有文件。
        List<String> list = new ArrayList<>();
        for (int i = 0; i < listing.getObjectSummaries().size(); i++) {
            String FILE_URL = "http://" + AliyunConfig.getBucket() + "." + AliyunConfig.getEndpoint() + "/" + listing.getObjectSummaries().get(i).getKey();
            list.add(FILE_URL);
        }
        // 关闭OSSClient。
        ossClient.shutdown();


//        ObjectListing objectListing = null;
//        int total = 0;
//        HashMap<Integer, String> markerMap = new HashMap<>();
//        try {
//            ObjectListing objectListing2 = null;
//            do {
//                String nextMarker2 = objectListing2 != null ? objectListing2.getNextMarker() : null;
//                ListObjectsRequest listObjectsRequest2 = new ListObjectsRequest(bucketName).withMarker(nextMarker2).withMaxKeys(100);
//                listObjectsRequest2.setPrefix(fileHost + "/");
//                objectListing2 = ossClient.listObjects(listObjectsRequest2);
//                total += (objectListing2 != null && objectListing2.getObjectSummaries() != null ? objectListing2.getObjectSummaries().size() : 0);
//                markerMap.put(markerMap.size() + 1, nextMarker2);
//            } while (objectListing2 != null && !StringUtils.isEmpty(objectListing2.getNextMarker()));
//
//            ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName).withMarker(nextMarker).withMaxKeys(100);
//
//            listObjectsRequest.setPrefix(fileHost + "/");
//
//            objectListing = ossClient.listObjects(listObjectsRequest);
//            for (int i = 0; i < objectListing.getObjectSummaries().size(); i++) {
//                String FILE_URL = "https://" + bucketName + "." + endpoint + "/" + objectListing.getObjectSummaries().get(i).getKey();
//                list.add(FILE_URL);
//            }
//
//        } catch (Exception e) {
//
//        } finally {
//            // 关闭client
//            ossClient.shutdown();
//        }

        return list;
    }

    /**
     * 删除文件
     * objectName key 地址
     *
     * @param filePath
     */
    public Boolean delFile(String filePath) {
        // 创建OSSClient实例。
        OSS ossClient = getOSSClient();
        // 删除Object.
        boolean exist = ossClient.doesObjectExist(AliyunConfig.getBucket(), filePath);
        if (!exist) {
            return false;
        }
        ossClient.deleteObject(AliyunConfig.getBucket(), filePath);
        ossClient.shutdown();
        return true;
    }

    /**
     * 批量删除
     *
     * @param keys
     */
    public Boolean delFileList(List<String> keys) {
        // 创建OSSClient实例。
        OSS ossClient = getOSSClient();
        try {
            // 删除文件。
            DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(new DeleteObjectsRequest(AliyunConfig.getBucket()).withKeys(keys));
            List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            ossClient.shutdown();
        }
        return true;

    }

    /**
     * 创建文件夹
     *
     * @param folder
     * @return
     */
    public String createFolder(String folder) {
        // 创建OSSClient实例。
        OSS ossClient = getOSSClient();
        // 文件夹名
        final String keySuffixWithSlash = folder;
        // 判断文件夹是否存在，不存在则创建
        if (!ossClient.doesObjectExist(AliyunConfig.getBucket(), keySuffixWithSlash)) {
            // 创建文件夹
            ossClient.putObject(AliyunConfig.getBucket(), keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));
            // 得到文件夹名
            OSSObject object = ossClient.getObject(AliyunConfig.getBucket(), keySuffixWithSlash);
            String fileDir = object.getKey();
            ossClient.shutdown();
            return fileDir;
        }
        return keySuffixWithSlash;
    }

    /**
     * 通过文件名下载文件
     *
     * @param objectName    要下载的文件名
     * @param localFileName 本地要创建的文件名
     */
    public void downloadFile(HttpServletResponse response, String objectName, String localFileName) throws Exception {
        // 创建OSSClient实例。
        OSS ossClient = getOSSClient();
        try {
            // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
            OSSObject ossObject = ossClient.getObject(AliyunConfig.getBucket() , objectName);
            // 读去Object内容  返回
            BufferedInputStream in = new BufferedInputStream(ossObject.getObjectContent());

            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            //通知浏览器以附件形式下载
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(objectName, "utf-8"));
            //BufferedOutputStream out=new BufferedOutputStream(new FileOutputStream(new File("f:\\a.txt")));
            byte[] car = new byte[1024];
            int L = 0;
            while ((L = in.read(car)) != -1) {
                out.write(car, 0, L);

            }
            if (out != null) {
                out.flush();
                out.close();
            }
            if (in != null) {
                in.close();
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭OSSClient。
            ossClient.shutdown();
        }
    }

    public String onlineSee(String key) {
        // 创建OSSClient实例。
        OSS ossClient = getOSSClient();
        // 设置URL过期时间为1小时
        Date expiration = new Date(new Date().getTime() + 3600 * 1000);
        // 临时地址
        URL url = ossClient.generatePresignedUrl(AliyunConfig.getBucket(), key, expiration);
        // 关闭OSSClient。
        ossClient.shutdown();
        return url.toString();
    }

    public Object onlinePreview(String key) {
        // 创建OSSClient实例。
        OSS ossClient = getOSSClient();

        // 设置视频截帧操作。文档页数默认是200，EndPage_-1任意
        String style = "imm/previewdoc,EndPage_-1";

        String filenameExtension = key.substring(key.lastIndexOf("."));
        if (filenameExtension.equalsIgnoreCase(".pdf")) {
            style = "imm/previewdoc,EndPage_-1,PdfVector_true";
        }
        // 指定过期时间为1小时。
        Date expiration = new Date(new Date().getTime() + 1000 * 60 * 60);
        GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(AliyunConfig.getBucket(), key, HttpMethod.GET);
        req.setExpiration(expiration);
        req.setProcess(style);
        URL signedUrl = ossClient.generatePresignedUrl(req);

        return signedUrl;
    }
}
